package com.evolved.automata.experimental.speech;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;

public class SpeechStateMachineTester {

	/**
	 * @param args
	 */
	
	private static StringBuilder MotionCount;
	private static int Step;
	private static String CurrentCommand;
	private static String CommandType;
	private static final HashMap<String,String> NumberTranslation;
	private static boolean skipUpdate=false;
	
	private static HashMap<String,StateActionPerformer> ActionMap;
	private static BlockingQueue<String> MessageQueue;
	private static BlockingQueue<Object> SpeechQueue;
	
	static 
	{
		NumberTranslation = new HashMap<String,String>();
		NumberTranslation.put("zero", "0");
		NumberTranslation.put("one", "1");
		NumberTranslation.put("two", "2");
		NumberTranslation.put("three", "3");
		NumberTranslation.put("four", "4");
		NumberTranslation.put("five", "5");
		NumberTranslation.put("six", "6");
		NumberTranslation.put("seven", "7");
		NumberTranslation.put("eight", "8");
		NumberTranslation.put("nine", "9");
		
		ActionMap = new HashMap<String,StateActionPerformer>();
		StateActionPerformer performer;
		String performerName;
		// Creating "initialize_new_motion"
		performerName="initialize_new_motion";
		performer = new StateActionPerformer()
		{
			public Object ProcessState(String statename, Object data)
			{
				Initialize((String)data);
				return null;
			}
		};
		ActionMap.put(performerName, performer);
		
		performerName="set_movement_type";
		performer = new StateActionPerformer()
		{
			public Object ProcessState(String statename, Object data)
			{
				SetMovementType((String)data);
				return null;
			}
		};
		ActionMap.put(performerName, performer);
		
		performerName="translate_number";
		performer = new StateActionPerformer()
		{
			public Object ProcessState(String statename, Object data)
			{
				return TranslateNumber((String)data);
				 
			}
		};
		ActionMap.put(performerName, performer);
		
		performerName="append_to_command_buffer";
		performer = new StateActionPerformer()
		{
			public Object ProcessState(String statename, Object data)
			{
				AppendToBuffer((String)data);
				return null;
			}
		};
		ActionMap.put(performerName, performer);
		
		performerName="translate_command_buffer";
		performer = new StateActionPerformer()
		{
			public Object ProcessState(String statename, Object data)
			{
				SetCommandBuffer();
				return null;
			}
		};
		ActionMap.put(performerName, performer);
		
		performerName="post_STEP_event";
		performer = new StateActionPerformer()
		{
			public Object ProcessState(String statename, Object data)
			{
				PostStep();
				return null;
			}
		};
		ActionMap.put(performerName, performer);
		
		performerName="perform_action";
		performer = new StateActionPerformer()
		{
			public Object ProcessState(String statename, Object data)
			{
				PerformAction();
				return null;
			}
		};
		ActionMap.put(performerName, performer);
		
		performerName="decrease_step";
		performer = new StateActionPerformer()
		{
			public Object ProcessState(String statename, Object data)
			{
				DecrementStep();
				return null;
			}
		};
		ActionMap.put(performerName, performer);
		
		performerName="choose_next_state";
		performer = new StateActionPerformer()
		{
			public Object ProcessState(String statename, Object data)
			{
				return ChooseNextState();
				
			}
		};
		ActionMap.put(performerName, performer);
		
		performerName="show_exception_message";
		performer = new StateActionPerformer()
		{
			public Object ProcessState(String statename, Object data)
			{
				ShowExceptionMessage((String)data);
				return null;
			}
		};
		ActionMap.put(performerName, performer);
		
		
		
	}
	
	private static void Initialize(String command)
	{
		MotionCount = new StringBuilder("");
		Step=0;
		CurrentCommand=command;
	}
	
	private static void SetMovementType(String mType)
	{
		CommandType=mType;
	}
	
	private static String TranslateNumber(String numberName)
	{
		return NumberTranslation.get(numberName.toLowerCase());
	}
	
	private static void AppendToBuffer(String number)
	{
		MotionCount.append(number);
	}
	
	private static void SetCommandBuffer()
	{
		Step= Integer.parseInt(MotionCount.toString());
	}
	
	private static void PostStep()
	{
		try
		{
			
			MessageQueue.put("step");
			
		}
		catch (Exception e)
		{
			
		}
	}
	
	private static void ShowExceptionMessage(String eventName)
	{
		System.out.println("The event "+ eventName + " is not appropriate.");
	}
	
	
	private static void PerformAction()
	{
		try
		{
			Thread.sleep(1000);
		}
		catch (Exception e)
		{
			
		}
		System.out.printf("Executing action %1$s %2$s for step %3$s\r\n",CurrentCommand,CommandType ,Step);
	}
	
	private static void DecrementStep()
	{
		Step--;
	}
	
	private static String ChooseNextState()
	{
		if (Step==0)
			return "[waiting_on_command]";
		else
		{
			PostStep();
			return "[executing_motion_until_complete]";
		}
	}
	
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		String stateConfigFileFullname="e:\\speech_state_flows.txt";
		String speechConfigFileFullName = "e:\\robot.speech.config.xml";
		MessageQueue= new LinkedBlockingQueue<String>();
		SpeechProcessor sprocessor = new SpeechProcessor(speechConfigFileFullName);
		SpeechQueue=sprocessor.GetSpeechQueue();
		
		int messageDelaySeconds=5;
		Thread speakingThread;
		Runnable speakingFunction;
		ParametricStateMachine smachine;
		speakingFunction = new Runnable()
		{
			public void run()
			{
				Object word;
				SpeechProcessor.SpeechResponse sResponse;
				try
				{
					word=SpeechQueue.take();
					sResponse=(SpeechProcessor.SpeechResponse)word;
					while (sResponse.responseType!=SpeechProcessor.SpeechResponseType.EXCEPTION &&
							sResponse.responseType!=SpeechProcessor.SpeechResponseType.EXITING)
					{
						if (sResponse.responseType==SpeechProcessor.SpeechResponseType.MISUNDERSTOOD)
							MessageQueue.put(".");
						else
							MessageQueue.put(sResponse.getResponseString().toLowerCase().trim());
						word=SpeechQueue.take();
						sResponse=(SpeechProcessor.SpeechResponse)word;
					}
				    MessageQueue.put("quit");
				}
				catch (Exception e)
				{
					
				}
			}
		};
		
		try
		{
			speakingThread= new Thread(speakingFunction);
			speakingThread.start();
			sprocessor.StartProcessing();
			smachine = new ParametricStateMachine(stateConfigFileFullname,"[final_state]","[waiting_on_command]",ActionMap,"[event_inappropriate_to_state]",MessageQueue,messageDelaySeconds*1000);
			smachine.ProcessStateMachine();
			speakingThread.interrupt();
			sprocessor.StopProcessing();
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
	}
	
	

}
